﻿/**
 * \file MainWindow.xaml.cs
 * \brief Classe MainWindow.xaml
 * \author ARTUR Vincent
 * \author LAPERDRIX Pierre
 * \version 1.0
 */

namespace WpfJeu
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Navigation;
    using System.Windows.Shapes;
    using System.ComponentModel;
    using Implem;
    using Interfaces;
    using System.Collections.ObjectModel;


    /**
     * \class MainWindow
     * \brief Objet representant le moteur graphique du jeu
     */
    public partial class MainWindow : Window
    {

        private bool loading;

        /*!< Partie du jeu en cours*/
        private Partie partie;

        /*!< Liste des VueUnite de la partie*/
        private Dictionary<Joueur,List<VueUnite>> listeVueUnite;

        /*!< Liste des VueVillePrincipale de la partie*/
        private Dictionary<Joueur,List<VueVillePrincipale>> listeVueVille;

        /*!< Liste des offesets de la vue de chaque joueur */
        private Dictionary<Joueur, KeyValuePair<double, double>> listeOffset;


        /*************************** Dependency Property permettant de gerer la vue detaille ***************************/

        /*!< Dependency Property _uniteEnCours contenant l'unite selectionnee par le joueur */
        public static DependencyProperty _uniteEnCours = DependencyProperty.Register("UniteEnCours", typeof(VueUnite), typeof(MainWindow));
        /*!< Propriete accedant a l'attribut _uniteEnCours */
        public VueUnite UniteEnCours
        {
            get { return (VueUnite)GetValue(_uniteEnCours); }
            set { this.SetValue(_uniteEnCours, value); }
        }


        /*!< Dependency Property _caseEnCours contenant la case selectionnee par le joueur */
        public static DependencyProperty _caseEnCours = DependencyProperty.Register("CaseEnCours", typeof(VueCase), typeof(MainWindow));
        /*!< Propriete accedant a l'attribut _caseEnCours */
        public VueCase CaseEnCours
        {
            get { return (VueCase)GetValue(_caseEnCours); }
            set { this.SetValue(_caseEnCours, value); }
        }


        /*!< Dependency Property _villeEnCours contenant la ville selectionnee par le joueur */
        public static DependencyProperty _villeEnCours = DependencyProperty.Register("VilleEnCours", typeof(VueVillePrincipale), typeof(MainWindow));
        /*!< Propriete accedant a l'attribut _villeEnCours */
        public VueVillePrincipale VilleEnCours
        {
            get { return (VueVillePrincipale)GetValue(_villeEnCours); }
            set { this.SetValue(_villeEnCours, value); }
        }


        /*!< Dependency Property _typeUnite contenant le type de l'unite selectionnee par le joueur */
        public static readonly DependencyProperty _typeUnite = DependencyProperty.Register("TypeUnite", typeof(string), typeof(MainWindow), new FrameworkPropertyMetadata(String.Empty));
        /*!< Propriete accedant a l'attribut _typeUnite */
        public string TypeUnite 
        { 
            get { return (string)GetValue(_typeUnite); } 
            set { SetValue(_typeUnite, value); }
        }


        /*!< Dependency Property _isEnseignant pour savoir si l'unite selectionnee est un enseignant
         * Cette Dependency Property contrôle l'affichage du bouton "Fonder une ville" dans la vue détaillée des unités*/       
        public static readonly DependencyProperty _isEnseignant= DependencyProperty.Register("IsEnseignant", typeof(bool), typeof(MainWindow), new FrameworkPropertyMetadata(false));
        /*!< Propriete accedant a l'attribut _isEnseignant */
        public bool IsEnseignant 
        { 
            get { return (bool)GetValue(_isEnseignant); } 
            set { SetValue(_isEnseignant, value); }
        }

        /*!< Dependency Property _aucuneUniteEnCours pour savoir si aucune unite est en cours de production sur la ville selectionnée
         * Cette Dependency Property contrôle l'affichage du bouton "Unité à produire" dans la vue détaillée des villes*/ 
        public static readonly DependencyProperty _aucuneUniteEnCours = DependencyProperty.Register("AucuneUniteEnCours", typeof(bool), typeof(MainWindow), new FrameworkPropertyMetadata(true));
        /*!< Propriete accedant a l'attribut _aucuneUniteEnCours */
        public bool AucuneUniteEnCours 
        { 
            get { return (bool)GetValue(_aucuneUniteEnCours); } 
            set { SetValue(_aucuneUniteEnCours, value); } 
        }


        /*!< Dependency Property _isUnite pour savoir si l'élément sélectionné est une unité
         * Cette Dependency Property contrôle l'affichage de la vue détaillée des unités*/ 
        public static readonly DependencyProperty _isUnite = DependencyProperty.Register("IsUnite", typeof(bool), typeof(MainWindow), new FrameworkPropertyMetadata(false));
        /*!< Propriete accedant a l'attribut _isUnite */
        public bool IsUnite { 
            get { return (bool)GetValue(_isUnite); } 
            set { SetValue(_isUnite, value); } 
        }

        /*!< Dependency Property _isCase pour savoir si l'élément sélectionné est une case
         * Cette Dependency Property contrôle l'affichage de la vue détaillée des cases*/
        public static readonly DependencyProperty _isCase = DependencyProperty.Register("IsCase", typeof(bool), typeof(MainWindow), new FrameworkPropertyMetadata(false));
        /*!< Propriete accedant a l'attribut _isCase */
        public bool IsCase { 
            get { return (bool)GetValue(_isCase); } 
            set { SetValue(_isCase, value); } 
        }

        /*!< Dependency Property _isVille pour savoir si l'élément sélectionné est une ville
        * Cette Dependency Property contrôle l'affichage de la vue détaillée des villes*/
        public static readonly DependencyProperty _isVille = DependencyProperty.Register("IsVille", typeof(bool), typeof(MainWindow), new FrameworkPropertyMetadata(false));
        /*!< Propriete accedant a l'attribut _isVille */
        public bool IsVille { 
            get { return (bool)GetValue(_isVille); } 
            set { SetValue(_isVille, value); } 
        }

        /*************************** Adresse relative des images pour la creation des cases sur la carte ***************************/
        /*< Uri utilise pour les cases Desert */
        private Uri desert;

        /*< Uri utilise pour les cases Montagne */
        private Uri montagne;

        /*< Uri utilise pour les cases Plaine */
        private Uri plaine;

        /*< Uri utilise pour les decorateurs Fer */
        private Uri fer;

        /*< Uri utilise pour les decorateurs Fruit */
        private Uri fruit;


        public static IDictionary<Position, VueCase> all = new Dictionary<Position,VueCase>();

        private static bool sugg = true;

        private static List<VueCase> high = new List<VueCase>();

        /*************************** Methodes de la classe MainWindow ***************************/


        /**
         * \fn public MainWindow(typeStrategie s, int nbJ, List<string> n, List<typeCivil> civi, List<Color> coul)
         * \brief Constructeur de MainWindow
         * \param s le type de stratégie de construction de la carte
         * \param nbJ le nombre de joueurs de la partie
         * \param civi la liste des civilisations pour chaque joueur
         * \param coul la liste des couleurs pour chaque joueur
         */
        public MainWindow(typeStrategie s, int nbJ, List<string> n, List<typeCivil> civi, List<Color> coul)
        {
            loading = false;
            //Creation des listes
            listeVueUnite = new Dictionary<Joueur,List<VueUnite>>();
            listeVueVille = new Dictionary<Joueur,List<VueVillePrincipale>>();
            listeOffset = new Dictionary<Joueur, KeyValuePair<double, double>>();

            //Creation de la partie
            MonteurPartie mP = new MonteurPartie();
            partie = mP.creerPartie(s, nbJ, n, civi,coul);
            InitializeComponent();
            

            //Affichage du message de debut de partie
            Xceed.Wpf.Toolkit.MessageBox.Show("A " + Partie.joueurCourant.Nom + " de jouer!", "Début de la partie", MessageBoxButton.OK, MessageBoxImage.Information);
            init();
        }

        public MainWindow(string filename)
        {
            //Creation des listes
            listeVueUnite = new Dictionary<Joueur, List<VueUnite>>();
            listeVueVille = new Dictionary<Joueur, List<VueVillePrincipale>>();
            listeOffset = new Dictionary<Joueur, KeyValuePair<double, double>>();

            //Creation de la partie
            loading = false;
            partie = new Partie();
            partie.load(filename);
            InitializeComponent();

            //Initialisation des images
            desert = new Uri("/WpfJeu;component/Ressources/terrains/desert.png", UriKind.Relative);
            montagne = new Uri("/WpfJeu;component/Ressources/terrains/montagne.png", UriKind.Relative);
            plaine = new Uri("/WpfJeu;component/Ressources/terrains/plaine.png", UriKind.Relative);

            fer = new Uri("/WpfJeu;component/Ressources/ressources/fer.png", UriKind.Relative);
            fruit = new Uri("/WpfJeu;component/Ressources/ressources/fruit.png", UriKind.Relative);

            //Initialisation de l'handler d'ajout d'element et de suppression d'element
            this.AddHandler(VueVillePrincipale.NouvelleUniteEvent, new RoutedEventHandler(ajoutVueUnite));
            this.AddHandler(VueVillePrincipale.NouvelleExpansionEvent, new RoutedEventHandler(ajoutVueVilleExpansion));
            this.AddHandler(VueCase.SuppressionEvent, new RoutedEventHandler(suppresionVueUnite));
            this.AddHandler(VueVillePrincipale.PriseEvent, new RoutedEventHandler(priseVille));

            //Gestion des clics sur les cases
            this.AddHandler(VueUnite.ClickUniteEvent, new RoutedEventHandler(gestionUniteEvent));
            this.AddHandler(VueCase.ClickCaseEvent, new RoutedEventHandler(gestionCaseEvent));
            this.AddHandler(VueVillePrincipale.ClickVilleEvent, new RoutedEventHandler(gestionVilleEvent));
            this.AddHandler(VueVilleExpansion.ClickExpansionEvent, new RoutedEventHandler(gestionExpansionEvent));

            load(filename);

            //Affichage du message de debut de partie
            Xceed.Wpf.Toolkit.MessageBox.Show("A " + Partie.joueurCourant.Nom + " de jouer!", "Début de la partie", MessageBoxButton.OK, MessageBoxImage.Information);

        }

        public void keyDown(object sender, KeyEventArgs e)
	    {
            if (sugg)
            {
                if (e.Key == Key.F2)
                {
                    List<Position> lcases = Carte.suggestion();

                    foreach (Position p in lcases)
                    {
                        all[p].highlight();
                        high.Add(all[p]);
                    }
                    sugg = false;

                }
            }
            else
            {
                if (e.Key == Key.F2)
                {
                    foreach (VueCase vc in high)
                    {
                        vc.unhighlight();
                    }
                    high.Clear();
                    sugg = true;

                } 
            }
            if (e.Key == Key.F5)
            {

                string filename = "toto.save";
                Microsoft.Win32.SaveFileDialog dlg = new Microsoft.Win32.SaveFileDialog();
                dlg.DefaultExt = ".save";
                dlg.Filter = "Civilisation Save File (.save)|*.save";
                if (dlg.ShowDialog() == true)
                {
                    filename = dlg.FileName;
                    partie.save(filename);

                    MessageBox.Show("La partie a été sauvegardée !");
                }

            }

            if (e.Key == Key.F6)
            {
                fenetreChargement(sender,e);                    
            }
            
            // Touche entrée pour terminer le tour
            if (e.Key == Key.Return)
            {
                finTour(sender, e);
            }

            if (e.Key == Key.Up)
            {
                if (UniteEnCours != null)
                {
                    if (listeCaseUnites.SelectedItems.Count > 1)
                    {
                        foreach (VueUnite vu in listeCaseUnites.SelectedItems)
                        {
                            vu.moveUp();
                            updateVueUnite();
                        }
                    }
                    else
                    {
                        UniteEnCours.moveUp();
                        updateVueUnite();
                    }
                }
            }
            if (e.Key == Key.Down)
            {
                if (UniteEnCours != null)
                {
                    if (listeCaseUnites.SelectedItems.Count > 1)
                    {
                        foreach (VueUnite vu in listeCaseUnites.SelectedItems)
                        {
                            vu.moveDown();
                            updateVueUnite();
                        }
                    }
                    else
                    {
                        UniteEnCours.moveDown();
                        updateVueUnite();
                    }
                }
            }
            if (e.Key == Key.Left)
            {
                if (UniteEnCours != null)
                {
                    if (listeCaseUnites.SelectedItems.Count > 1)
                    {
                        foreach (VueUnite vu in listeCaseUnites.SelectedItems)
                        {
                            vu.moveLeft();
                            updateVueUnite();
                        }
                    }
                    else
                    {
                        UniteEnCours.moveLeft();
                        updateVueUnite();
                    }
                }
            }
            if (e.Key == Key.Right)
            {
                if (UniteEnCours != null)
                {
                    if (listeCaseUnites.SelectedItems.Count > 1)
                    {
                        foreach (VueUnite vu in listeCaseUnites.SelectedItems)
                        {
                            vu.moveRight();
                            updateVueUnite();
                        }
                    }
                    else
                    {
                        UniteEnCours.moveRight();
                        updateVueUnite();
                    }
                }
            }


            Keyboard.Focus(this);
	    }

        private void updateVueUnite()
        {
            VueUnite tmp = UniteEnCours;
            UniteEnCours = null;
            UniteEnCours = tmp;
            IsCase = false;
        }

        private void fenetreChargement(object sender, RoutedEventArgs e){
            string filename = "toto.save";
            // Create OpenFileDialog
            Microsoft.Win32.OpenFileDialog dlg = new Microsoft.Win32.OpenFileDialog();

            // Set filter for file extension and default file extension
            dlg.DefaultExt = ".save";
            dlg.Filter = "Civilisation Save File (.save)|*.save";

            // Display OpenFileDialog by calling ShowDialog method
            Nullable<bool> result = dlg.ShowDialog();
            

            // Get the selected file name and display in a TextBox
            if (result == true){
                filename = dlg.FileName;
                load(filename);
            }
        }

        private void load(string filename)
        {
            partie.load(filename);
            grille.Children.Clear();
            all.Clear();

            //On recupere la carte
            Case[][] cases = Carte.Cases;

            //Declaration des X (Rows) et des Y (Columns)
            for (int i = 0; i < cases[0].Length; i++)
            {
                RowDefinition ligneDef = new RowDefinition();
                grille.RowDefinitions.Add(ligneDef);
                ColumnDefinition colDef = new ColumnDefinition();
                grille.ColumnDefinitions.Add(colDef);
            }

            //Remplissage des listes

            for (int x = 0; x < Carte.Cases[0].Length; x++)
            {
                for (int y = 0; y < Carte.Cases[0].Length; y++)
                {
                    var square = creerCase(x, y, Carte.Cases[x][y]);
                    grille.Children.Add(square);
                    all.Add(new Position(x, y), square);
                }

            }

            foreach (Joueur j in partie.Joueurs)
            {
                listeVueUnite.Add(j, new List<VueUnite>());
                listeVueVille.Add(j, new List<VueVillePrincipale>());

                //Creation des vues des unites
                if (j.Directeur != null)
                {
                    VueUnite dir = new VueUnite((Unite)j.Directeur);
                    all[dir.Unite.Posit].nouvelleUnite(dir);
                    listeVueUnite[j].Add(dir);
                }
                foreach (IEtudiant et in j.Etudiants)
                {
                    VueUnite etu = new VueUnite((Unite)et);
                    all[etu.Unite.Posit].nouvelleUnite(etu);
                    listeVueUnite[j].Add(etu);
                }
                foreach (IEnseignant en in j.Enseignants)
                {
                    VueUnite ens = new VueUnite((Unite)en);
                    all[ens.Unite.Posit].nouvelleUnite(ens);
                    listeVueUnite[j].Add(ens);
                }

                //Creation des vues des villes
                foreach (Ville ville in j.Villes)
                {
                    VueVillePrincipale vvp = new VueVillePrincipale(ville);
                    all[vvp.Ville.PositCentrale].ajoutVille(vvp);
                    listeVueVille[j].Add(vvp);
                    for (int i = 0; i < 5; i++)
                    {
                        for (int k = 0; k < 5; k++)
                        {
                            if (ville.VilleExt[i][k] == 1)
                            {
                                Position p = new Position(ville.PositCentrale.X + i - 2, ville.PositCentrale.Y + k - 2);
                                VueVilleExpansion vve = new VueVilleExpansion(vvp, p);
                                all[p].ajoutVille(vve);


                            }
                        }
                    }
                }  
            }

            this.updateVueJoueurCourant();
            updateFog();
        }

        /**
         * \fn private void init()
         * \brief Méthode qui charge les différents éléments de la MainWindow
         */
        private void init()
        {
            //Initialisation des images
            desert = new Uri("/WpfJeu;component/Ressources/terrains/desert.png", UriKind.Relative);
            montagne = new Uri("/WpfJeu;component/Ressources/terrains/montagne.png", UriKind.Relative);
            plaine = new Uri("/WpfJeu;component/Ressources/terrains/plaine.png", UriKind.Relative);

            fer = new Uri("/WpfJeu;component/Ressources/ressources/fer.png", UriKind.Relative);
            fruit = new Uri("/WpfJeu;component/Ressources/ressources/fruit.png", UriKind.Relative);

            //Initialisation de l'handler d'ajout d'element et de suppression d'element
            this.AddHandler(VueVillePrincipale.NouvelleUniteEvent, new RoutedEventHandler(ajoutVueUnite));
            this.AddHandler(VueVillePrincipale.NouvelleExpansionEvent, new RoutedEventHandler(ajoutVueVilleExpansion));
            this.AddHandler(VueCase.SuppressionEvent, new RoutedEventHandler(suppresionVueUnite));
            this.AddHandler(VueVillePrincipale.PriseEvent, new RoutedEventHandler(priseVille));

            //Gestion des clics sur les cases
            this.AddHandler(VueUnite.ClickUniteEvent, new RoutedEventHandler(gestionUniteEvent));
            this.AddHandler(VueCase.ClickCaseEvent, new RoutedEventHandler(gestionCaseEvent));
            this.AddHandler(VueVillePrincipale.ClickVilleEvent, new RoutedEventHandler(gestionVilleEvent));
            this.AddHandler(VueVilleExpansion.ClickExpansionEvent, new RoutedEventHandler(gestionExpansionEvent));

            if (!loading)
            {
                all.Clear();

                //On recupere la carte
                Case[][] cases = Carte.Cases;

                //Declaration des X (Rows) et des Y (Columns)
                for (int i = 0; i < cases[0].Length; i++)
                {
                    RowDefinition ligneDef = new RowDefinition();
                    grille.RowDefinitions.Add(ligneDef);
                    ColumnDefinition colDef = new ColumnDefinition();
                    grille.ColumnDefinitions.Add(colDef);
                }

                // Remplissage de la vue
                for (int x = 0; x < cases[0].Length; x++)
                {
                    for (int y = 0; y < cases[0].Length; y++)
                    {
                        var square = creerCase(x, y, cases[x][y]);
                        if (!loading) all.Add(new Position(x, y), square);
                        grille.Children.Add(square);
                    }

                }

                //Creation des VueUnite a partir des unites presentes sur le plateau
                foreach (Joueur j in partie.Joueurs)
                {
                    //Creation de la valeur d'offset
                    double x = (double)((Unite)(j.Etudiants[0])).Posit.X * 50 -225 ;
                    double y = (double)((Unite)(j.Etudiants[0])).Posit.Y * 50 -225;
                    KeyValuePair<double, double> offset = new KeyValuePair<double, double>(x,y);
                    listeOffset.Add(j, offset);


                    //Creation des listes pour chaque joueur dans les dictionary
                    if (!loading) listeVueUnite.Add(j, new List<VueUnite>());
                    if (!listeVueVille.ContainsKey(j))
                    {
                        listeVueVille.Add(j, new List<VueVillePrincipale>());
                    }

                    if (!loading)
                    {
                        //Ajout du premier etudiant du joueur sur la carte
                        VueUnite vu1 = new VueUnite((Unite)j.Etudiants[0]);
                        //grille.Children.Add(vu1);
                        listeVueUnite[j].Add(vu1);

                        VueCase v1 = grille.Children.Cast<VueCase>().First(f => Grid.GetRow(f) == vu1.Pos.X && Grid.GetColumn(f) == vu1.Pos.Y);
                        v1.nouvelleUnite(vu1);
                        //Ajout du premier enseignant du joueur sur la carte
                        VueUnite vu2 = new VueUnite((Unite)j.Enseignants[0]);
                        //grille.Children.Add(vu2);
                        listeVueUnite[j].Add(vu2);

                        VueCase v2 = grille.Children.Cast<VueCase>().First(f => Grid.GetRow(f) == vu2.Pos.X && Grid.GetColumn(f) == vu2.Pos.Y);
                        v2.nouvelleUnite(vu2);

                        loading = false;
                    }

                }

                //On met a jour les VueUnite et les VueVillePrincpale en fonction du premier joueurCourant
                updateVueJoueurCourant();

                //Initialisation du FOG
                updateFog();

                //On positionne la vue
                scroll.ScrollToVerticalOffset(listeOffset[Partie.joueurCourant].Value);
                scroll.ScrollToHorizontalOffset(listeOffset[Partie.joueurCourant].Key);           
            }
        }

        private void hideAll()
        {
            foreach (VueCase vc in all.Values)
            {
                vc.hide();
            }
        }

        /**
         * \fn private VueCase creerCase(int x, int y, Case square)
         * \brief Crée une VueCase
         * \param x la position x dans la grille de la VueCase
         * \param y la position y dans la grille de la VueCase
         * \param square le type de la case à créer
         * \return la VueCase crée
         */
        private VueCase creerCase(int x, int y, Case square)
        {
            VueCase vc;
            if (square is Desert)
            {
                vc = new VueCase(desert, null, square, x, y);
            }
            else if (square is Montagne)
            {
                vc = new VueCase(montagne, null, square, x, y);
            }
            else if (square is Plaine)
            {
                vc = new VueCase(plaine, null, square, x, y);
            }
            else
            {
                DecorateurCase cf;
                Uri deco;
                if (square is CaseFruit)
                {
                    cf = (CaseFruit)square;
                    deco = fruit;
                }
                else
                {
                    cf = (CaseFer)square;
                    deco = fer;
                }

                if (cf.Square is Desert)
                {
                    vc = new VueCase(desert, deco, square, x, y);
                }
                else if (cf.Square is Montagne)
                {
                    vc = new VueCase(montagne, deco, square, x, y);
                }
                else
                {
                    vc = new VueCase(plaine, deco, square, x, y);
                }
            }


            //Ajout de la position de l'image dans la grille
            Grid.SetColumn(vc, y);
            Grid.SetRow(vc, x);


            // Tag : reference par defaut sur la case logique
            vc.Tag = square;

            return vc;
        }



        /**
         * \fn public void ajoutVueUnite(object sender, RoutedEventArgs args)
         * \brief Handler permettant de rajouter une VueUnite
         * \param sender
         * \param args
         */
        public void ajoutVueUnite(object sender, RoutedEventArgs args)
        {
            VueUnite vu = (VueUnite)args.OriginalSource;

            //Ajout a la liste des vue unites de la partie
            listeVueUnite[Partie.joueurCourant].Add(vu);

            //Ajout a la case ou l'unite a ete cree
            VueCase v = grille.Children.Cast<VueCase>().First(f => Grid.GetRow(f) == vu.Pos.X && Grid.GetColumn(f) == vu.Pos.Y);
            v.nouvelleUnite(vu);

            //Mise a jouer de l'attribut AucuneUniteEnCours de la ville
            AucuneUniteEnCours = true;

            //Permet de mettre a jour la vue apres le changement
            VueVillePrincipale tmp = VilleEnCours;
            VilleEnCours = null;
            VilleEnCours = tmp;

            args.Handled = true;
        }


        /**
         * \fn public void ajoutVueVilleExpansion(object sender, RoutedEventArgs args)
         * \brief Handler permettant de rajouter une VueVilleExpansion
         * \param sender
         * \param args
         */
        public void ajoutVueVilleExpansion(object sender, RoutedEventArgs args)
        {
            VueVilleExpansion vve = (VueVilleExpansion)args.OriginalSource;
            VueCase vc = grille.Children.Cast<VueCase>().First(f => Grid.GetRow(f) == vve.Pos.X && Grid.GetColumn(f) == vve.Pos.Y);
            vc.ajoutVille(vve);

            args.Handled = true;
        }

        /**
         * \fn public void deplacerUnite(VueUnite vu, Position p)
         * \brief Déplace l'unité si possible
         * \param vu la VueUnite de l'unité à déplacer
         * \param p la position vers laquelle l'unité veut se déplacer
         */
        public void deplacerUnite(VueUnite vu, Position p)
        {
            int x = vu.Pos.X;
            int y = vu.Pos.Y;
            if (vu.Unite != null)
            {
                vu.Unite.seDeplacer(p);

                //On recontrole que l'unite n'est pas morte dans la fonction seDeplacer
                if (vu.Unite != null && (vu.Unite.Posit.X != x || vu.Unite.Posit.Y != y))
                {
                    vu.Pos = vu.Unite.Posit;

                    //Deplacement de l'element d'une case v1 a une case v2
                    VueCase v1 = grille.Children.Cast<VueCase>().First(e => Grid.GetRow(e) == x && Grid.GetColumn(e) == y);
                    VueCase v2 = grille.Children.Cast<VueCase>().First(e => Grid.GetRow(e) == vu.Pos.X && Grid.GetColumn(e) == vu.Pos.Y);

                    v1.departUnite(vu);
                    v2.nouvelleUnite(vu);
                }
            }

            //Permet de mettre a jour les proprietes apres un deplacement
            VueUnite tmp = UniteEnCours;
            UniteEnCours = null;
            UniteEnCours = tmp;
            IsCase = false;
            updateVueJoueurCourant();

            updateFog();

            Keyboard.Focus(this);
        }


        /**
         * \fn public void setUniteEnCours(VueUnite vu)
         * \brief Met à jour l'unité sélectionnée par le joueur
         * \param vu la VueUnite de l'unité sélectionnée
         */
        public void setUniteEnCours(VueUnite vu)
        {
            UniteEnCours = vu;
            IsUnite = true;
            IsVille = false;
            //IsCase = false;

            //On fait disparaitre le nombre d'unites selectionnees
            nombreUnites.Visibility = Visibility.Collapsed;

            if (vu.Unite is IEnseignant)
            {
                IsEnseignant = true;
                TypeUnite = "Enseignant";
            }
            else
            {
                IsEnseignant = false;
                if (vu.Unite is IEtudiant)
                {
                    TypeUnite = "Etudiant";
                }
                else
                {
                    TypeUnite = "Directeur";
                }
            }
        }

        /**
         * \fn public void setCaseEnCours(VueCase vc)
         * \brief Met à jour la case sélectionnée par le joueur
         * \param vc la VueCase de la case sélectionnée
         */
        public void setCaseEnCours(VueCase vc)
        {
            CaseEnCours = vc;
            IsUnite = false;
            IsVille = false;
            IsCase = true;

            //On fait disparaitre le nombre d'unites selectionnees
            nombreUnites.Visibility = Visibility.Collapsed;

            affichaeListeUnites();
        }

        /**
         * \fn public void setVilleEnCours(VueVillePrincipale vvp)
         * \brief Met à jour la ville sélectionnée par le joueur
         * \param vvp la VueVillePrincipale de la ville sélectionnée
         */
        public void setVilleEnCours(VueVillePrincipale vvp)
        {
            VilleEnCours = vvp;
            IsUnite = false;
            IsVille = true;
            IsCase = false;

            //On fait disparaitre le nombre d'unites selectionnees
            nombreUnites.Visibility = Visibility.Collapsed;
        }


        /**
         * \fn public void affichaeListeUnites()
         * \brief Affiche la liste des unites dans la vue détaillée
         */
        public void affichaeListeUnites()
        {
            listeCaseUnites.Items.Clear();
            listeCaseUnitesPlusDeMouv.Items.Clear();
            
            if (CaseEnCours.Unites.Count > 0)
            {
                foreach (VueUnite vu in CaseEnCours.Unites)
                {
                    if (vu.Unite.MovRest == 0)
                    {
                        listeCaseUnitesPlusDeMouv.Items.Add(vu);
                    }
                    else
                    {
                        listeCaseUnites.Items.Add(vu);
                    }
                }
            }

            if (listeCaseUnites.HasItems)
            {
                listeCaseUnites.Visibility = Visibility.Visible;
            }
            else
            {
                listeCaseUnites.Visibility = Visibility.Collapsed;
            }

            if (listeCaseUnitesPlusDeMouv.HasItems)
            {
                listeCaseUnitesPlusDeMouv.Visibility = Visibility.Visible;
            }
            else
            {
                listeCaseUnitesPlusDeMouv.Visibility = Visibility.Collapsed;
            }

            Keyboard.Focus(this);
        }
        
        /**
         * \fn public void gestionUniteEvent(object sender, RoutedEventArgs e)
         * \brief Gère les clics sur les unités
         * \param sender
         * \param e la VueUnite qui a été cliquée
         */
        public void gestionUniteEvent(object sender, RoutedEventArgs e)
        {
            VueUnite vu = e.OriginalSource as VueUnite;
            this.CaseEnCours = null;
            this.VilleEnCours = null;
            IsCase = false;
            this.setUniteEnCours(vu);
            e.Handled = true;

            Keyboard.Focus(this);
        }

        /**
         * \fn public void gestionCaseEvent(object sender, RoutedEventArgs e)
         * \brief Gère les clics sur les cases
         * \param sender
         * \param e la VueCase qui a été cliquée
         */
        public void gestionCaseEvent(object sender, RoutedEventArgs e)
        {
            Console.WriteLine();
            Console.WriteLine(Keyboard.FocusedElement);
            Console.WriteLine();

            VueCase vc = e.OriginalSource as VueCase;
            
            //Affiche l'information de la case si les unites selectionnees ne peuvent plus se deplacer
            bool movRestant = false;
            foreach (VueUnite vu in listeCaseUnites.SelectedItems)
            {
                movRestant |= (vu.Unite.MovRest > 0);
            }
            if (UniteEnCours != null && UniteEnCours.Unite.MovRest > 0) movRestant = true;

            if (UniteEnCours == null)
            {
                this.VilleEnCours = null;
                this.setCaseEnCours(vc);
            }
            else if (this.UniteEnCours.Pos.posProche(vc.Pos) && movRestant && this.UniteEnCours.AppartientJoueurCourant && 
                (this.UniteEnCours.Pos.X != vc.Pos.X || this.UniteEnCours.Pos.Y != vc.Pos.Y))
            {
                if (listeCaseUnites.SelectedItems.Count > 1)
                {
                    foreach (VueUnite vu in listeCaseUnites.SelectedItems)
                    {
                        this.deplacerUnite(vu,vc.Pos);
                    }
                }
                else
                {
                    this.deplacerUnite(UniteEnCours,vc.Pos);
                }
            }
            else
            {
                this.UniteEnCours = null;
                this.VilleEnCours = null;
                this.setCaseEnCours(vc);
            }
            e.Handled = true;

            Keyboard.Focus(this);
        }

        /**
         * \fn public void gestionVilleEvent(object sender, RoutedEventArgs e)
         * \brief Gère les clics sur les villes (VueVillePrincipale)
         * \param sender
         * \param e la VueVillePrincipale qui a été cliquée
         */
        public void gestionVilleEvent(object sender, RoutedEventArgs e)
        {
            VueVillePrincipale vvp = e.OriginalSource as VueVillePrincipale;
            this.CaseEnCours = null;
            this.UniteEnCours = null;
            this.setVilleEnCours(vvp);
            if (vvp.Ville.UniteEnCours != typeProduction.aucune)
            {
                AucuneUniteEnCours = false;
            }
            else
            {
                AucuneUniteEnCours = true;
            }
            e.Handled = true;
        }

        /**
         * \fn public void gestionExpansionEvent(object sender, RoutedEventArgs e)
         * \brief Gère les clics sur les villes (VueVilleExpansion)
         * \param sender
         * \param e la VueVilleExpansion qui a été cliquée
         */
        public void gestionExpansionEvent(object sender, RoutedEventArgs e)
        {
            VueVilleExpansion vve = e.OriginalSource as VueVilleExpansion;
            this.CaseEnCours = null;
            this.UniteEnCours = null;
            this.setVilleEnCours(vve.Vvp);
            e.Handled = true;
        }


        /**
         * \fn private void finTour(object sender, RoutedEventArgs e)
         * \brief Appelle la fin de tour et change le joueur courant
         * \param sender
         * \param e
         */
        private void finTour(object sender, RoutedEventArgs e)
        {
            //Mise a zero
            this.IsUnite = false;
            this.UniteEnCours = null;
            this.IsCase = false;
            this.CaseEnCours = null;
            this.IsVille = false;
            this.VilleEnCours = null;
            this.listeCaseUnites.Items.Clear();
            this.listeCaseUnitesPlusDeMouv.Items.Clear();

            //Sauvegarde de l'offset
            double x = scroll.VerticalOffset;
            double y = scroll.HorizontalOffset;
            listeOffset[Partie.joueurCourant] = new KeyValuePair<double, double>(x, y);

            //Appelle de la fin de tour
            partie.finTour();

            //On met a jour les VueUnite et les VueVillePrincpale en fonction du nouveau joueurCourant
            updateVueJoueurCourant();

            //Reinitialisation du FOG
            updateFog();

            //Positionnement de la vue du scroller
            if (listeOffset.ContainsKey(Partie.joueurCourant))
            {
                scroll.ScrollToVerticalOffset(listeOffset[Partie.joueurCourant].Key);
                scroll.ScrollToHorizontalOffset(listeOffset[Partie.joueurCourant].Value);
            }

            //On annonce le joueur suivant
            Xceed.Wpf.Toolkit.MessageBox.Show("A " + Partie.joueurCourant.Nom + " de jouer!", "Changement de joueur", MessageBoxButton.OK, MessageBoxImage.Information);
        }

        private void updateFog()
        {
            hideAll();
            
            foreach (List<VueVillePrincipale> liste in listeVueVille.Values)
            {
                foreach (VueVillePrincipale vvp in liste)
                {
                    all[vvp.Ville.PositCentrale].unhideVisible();
                }
            }
            foreach (VueUnite vu in listeVueUnite[Partie.joueurCourant])
            {
                all[vu.Pos].unhideVisible();
            }


        }

        /**
         * \fn private void updateVueJoueurCourant()
         * \brief Mise à jour des VueUnites et des VueVillePrincpales en fonction du joueur courant
         */
        private void updateVueJoueurCourant()
        {
            //MAJ des VueUnite
            foreach (List<VueUnite> v in listeVueUnite.Values)
            {
                foreach (VueUnite vu in v)
                {
                    if (vu.Unite.JoueurProprietaire == Partie.joueurCourant)
                    {
                        vu.AppartientJoueurCourant = true;
                    }
                    else
                    {
                        vu.AppartientJoueurCourant = false;
                    }
                }
            }

            //MAJ des VueVillePrincpale
            foreach (List<VueVillePrincipale> v in listeVueVille.Values)
            {
                foreach (VueVillePrincipale vvp in v)
                {
                    if (vvp.Ville.JoueurProprietaire == Partie.joueurCourant)
                    {
                        vvp.AppartientJoueurCourant = true;
                    }
                    else
                    {
                        vvp.AppartientJoueurCourant = false;
                    }
                }
            }
        }

        /**
         * \fn private void fonderVille(object sender, RoutedEventArgs e)
         * \brief Crée une ville sur la carte appartenant au joueur courant
         * \param sender
         * \param e
         */
        private void fonderVille(object sender, RoutedEventArgs e)
        {
            IEnseignant tmp = (IEnseignant)UniteEnCours.Unite;

            Ville v = tmp.fonderVille();
            if (v != null)
            {
                VueVillePrincipale vvp = new VueVillePrincipale(v);
                VueCase vc = grille.Children.Cast<VueCase>().First(f => Grid.GetRow(f) == vvp.Ville.PositCentrale.X && Grid.GetColumn(f) == vvp.Ville.PositCentrale.Y);
                vc.ajoutVille(vvp);
                listeVueVille[Partie.joueurCourant].Add(vvp);

                //Ouvre une fenetre pour demander nom ville
                NomVille nv = new NomVille();
                if (nv.ShowDialog() == true)
                {
                    v.Nom = nv.Nom();
                }
            }
            else
            {
                MessageBox.Show("Impossible de fonder une ville sur le territoire d'une autre ville");
            }
            updateVueJoueurCourant();

        }

        /**
         * \fn private void changementProduction(object sender, RoutedEventArgs e)
         * \brief Donne accès au changement de la production en cours d'une ville
         * \param sender
         * \param e
         */
        private void changementProduction(object sender, RoutedEventArgs e)
        {
            //Si une unite est en cours de production, on demande a l'utilisateur s'il veut l'arreter
            if (VilleEnCours.Ville.UniteEnCours != typeProduction.aucune)
            {
                string messageBoxText = "Une unité est déjà en cours de création. Voulez-vous arrêter la production de cette unité?";
                string caption = "Unité en production";
                MessageBoxButton button = MessageBoxButton.YesNo;
                MessageBoxImage icon = MessageBoxImage.Question;

                // Affiche la MessageBox
                MessageBoxResult result = MessageBox.Show(messageBoxText, caption, button, icon);

                // Traitement du résultat
                switch (result)
                {
                    case MessageBoxResult.Yes:
                        choixProduction();
                        break;
                    case MessageBoxResult.No:
                        // L'utilisateur a choisi de ne pas arreter la production
                        break;
                }
            }
            else
            {
                choixProduction();
            }

        }

        /**
         * \fn private void choixProduction()
         * \brief Donne un choix d'unité à produire au joueur
         */
        private void choixProduction()
        {
            //Regarde si le joueur Courant possede un directeur
            bool directeurPresent = true;
            if (Partie.joueurCourant.Directeur == null) directeurPresent = false;

            //Creation d'une ListeUnite
            ListeUnite lu = new ListeUnite(directeurPresent);

            if (lu.ShowDialog() == true)
            {
                //Met a jour le type de la production
                VilleEnCours.Ville.setProduction(lu.Type);
               
                //Met a jour l'attribut AucuneUniteEnCours
                AucuneUniteEnCours = false;

                //Permet de mettre a jour la vue apres le changement
                VueVillePrincipale tmp = VilleEnCours;
                VilleEnCours = null;
                VilleEnCours = tmp;
               
            }

            
        }

        /**
         * \fn private void finProduction(object sender, RoutedEventArgs e)
         * \brief Met à jour la vue détaillée quand une unité a été produite
         * \param sender
         * \param e
         */
        private void finProduction(object sender, RoutedEventArgs e)
        {
            //Met a jour le type de la production
            VilleEnCours.Ville.setProduction(typeProduction.aucune);

            //Met a jour l'attribut AucuneUniteEnCours
            AucuneUniteEnCours = true;

            //Permet de mettre a jour la vue apres le changement
            VueVillePrincipale tmp = VilleEnCours;
            VilleEnCours = null;
            VilleEnCours = tmp;
        }


        /**
         * \fn private void affichageVueGloable(object sender, RoutedEventArgs e)
         * \brief Affiche des statistiques gloables sur le jeu
         * \param sender
         * \param e
         */
        private void affichageVueGloable(object sender, RoutedEventArgs e)
        {
            VueGlobale c = new VueGlobale(listeVueUnite, listeVueVille);
            c.Show();
        }

        /**
         * \fn private void listeCaseUnites_SelectionChanged(object sender, SelectionChangedEventArgs e)
         * \brief Met à jour la vue détaillée en fonction des unités sélectionnées par le joueur dans la liste des unités qui peuvent encore se déplacer
         * \param sender
         * \param e
         */
        private void listeCaseUnites_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (listeCaseUnites.SelectedItem != null)
            {
                setUniteEnCours((VueUnite) listeCaseUnites.SelectedItem);
            }
            if (listeCaseUnites.SelectedItems.Count > 1)
            {
                IsUnite = false;
                //Affichage du nombre d'unites selectionnes
                nombreUnites.Text = listeCaseUnites.SelectedItems.Count + " unités sélectionnées";
                nombreUnites.Visibility = Visibility.Visible;
            }

            Keyboard.Focus(this);
        }

        /**
         * \fn private void listeCaseUnitesPlusDeMouv_SelectionChanged(object sender, SelectionChangedEventArgs e)
         * \brief Met à jour la vue détaillée en fonction des unités sélectionnées par le joueur dans la liste des unités qui ne peuvent plus se déplacer
         * \param sender
         * \param e
         */
        private void listeCaseUnitesPlusDeMouv_SelectionChanged(object sender, SelectionChangedEventArgs e)
         {
            if (listeCaseUnitesPlusDeMouv.SelectedItem != null)
            {
                setUniteEnCours((VueUnite)listeCaseUnitesPlusDeMouv.SelectedItem);
            }
            if (listeCaseUnitesPlusDeMouv.SelectedItems.Count > 1)
            {
                IsUnite = false;
                //Affichage du nombre d'unites selectionnes
                nombreUnites.Text = listeCaseUnitesPlusDeMouv.SelectedItems.Count + " unités sélectionnées";
                nombreUnites.Visibility = Visibility.Visible;
            }
        }

        /**
         * \fn public void suppresionVueUnite(object sender, RoutedEventArgs e)
         * \brief Supprime la VueUnite quand une unité a été vaincue
         * \param sender
         * \param e la VueUnite asociée à l'unité vaincue
         */
        public void suppresionVueUnite(object sender, RoutedEventArgs e)
        {
            VueUnite vu = e.OriginalSource as VueUnite;
            Joueur jProprietaire = vu.Unite.JoueurProprietaire;

            //Suppression de la liste d'unites de la VueCase
            VueCase vc = grille.Children.Cast<VueCase>().First(f => Grid.GetRow(f) == vu.Pos.X && Grid.GetColumn(f) == vu.Pos.Y);
            vc.departUnite(vu);

            //Suppression de la liste d'unites du joueur au niveau de l'IHM
            this.listeVueUnite[jProprietaire].Remove(vu);

            //Suppression de l'unite de la vue (controle supplementaire)
            vu.Unite = null;

            //Verification si le joueur qui a perdu une unite a encore une unite
            if (this.listeVueUnite[jProprietaire].Count == 0 && this.listeVueVille[jProprietaire].Count ==0)
            {
                suppressionJoueur(jProprietaire);
            }
            updateVueJoueurCourant();
        }

        public void priseVille(object sender, RoutedEventArgs e)
        {
            KeyValuePair<Joueur, VueVillePrincipale> tmp = (KeyValuePair<Joueur, VueVillePrincipale>)e.OriginalSource;
            VueVillePrincipale vvp = tmp.Value;
            listeVueVille[tmp.Key].Remove(vvp);
            listeVueVille[vvp.Ville.JoueurProprietaire].Add(vvp);

            if (listeVueVille[tmp.Key].Count == 0 && listeVueUnite[tmp.Key].Count == 0)
            {
                suppressionJoueur(tmp.Key);
            }

        }

        /**
        * \fn public void suppressionJoueur(Joueur j)
        * \brief Supprime le joueur vaincu du jeu et vérifie le nombre joueur restant
        * \param j le joueur vaincu
        */
        public void suppressionJoueur(Joueur j)
        {
            //Suppression du joueur dans le modele
            partie.joueurElimine(j);

            //Suppression du joueur dans les listes de l'IHM
            this.listeVueUnite.Remove(j);
            this.listeVueVille.Remove(j);

            if (partie.NbJoueurs == 1)
            {
                Joueur gagnant = partie.Joueurs[0];
                Xceed.Wpf.Toolkit.MessageBox.Show("Félicitations " + gagnant.Nom + "!\nVous avez gagné la partie!");

                this.Close();
            }
            updateVueJoueurCourant();
        }

        private void affichageManuel(object sender, RoutedEventArgs e)
        {
            // Instance de la classe Process
            System.Diagnostics.Process proc = new System.Diagnostics.Process();
            // Nom du fichier dont l'extension est connue du shell à ouvrir
            proc.StartInfo.FileName = "userdoc.pdf";
            // Démarrage du processus.
            // Notepad, si il est associé aux fichiers .txt,
            // sera lancé et ouvrira le fichier monfichier.txt
            proc.Start();
            // On libère les ressources dont on a plus besoin.
            proc.Close(); // Attention Close ne met pas fin au processus.
        }

    }



}

